package dbservice

import (
	"src/zeus/dbservice/redislib"
	"src/zeus/logger"
	"sync"
	"time"

	"github.com/spf13/viper"
)

var (
	//login的数据缓存 所有区共用 0
	loginPool *redislib.RedisAccess
	//dbserver使用的redis 一个区一个 1
	lgplayerpool *redislib.RedisAccess
	// DBValid DB是否正常
	DBValid = true

	//用户的SESSION信息 所有区共用 2
	sessionPool *redislib.RedisAccess
	//服务器上Entity对象信息注册 包括用户路由信息和场景注册、本区副本 一个区一个 6
	entityPool *redislib.RedisAccess

	// SrvRedisValid Cache是否正常
	SrvRedisValid = true

	// 单实例redis连接池
	//一个区的唯一信息 3
	singletionPool *redislib.RedisAccess
	// SingletonRedisValid 单实例是否正常
	SingletonRedisValid = true

	//第三方订单redis
	//用于处理第三方发来的订单信息 一个区的唯一信息 4
	orderPool *redislib.RedisAccess

	// 排名使用的redis
	// 用于排名系统 一个区的唯一信息 5
	rankPool *redislib.RedisAccess
	//匹配使用的Redis
	matchPool     *redislib.RedisAccess
	pvpResultPool *redislib.RedisAccess

	redisRWMu sync.RWMutex
	// RankRedisValid 排名是否正常
	RankRedisValid = true
)

// InitAllRedis 连接全部的Redis
func InitAllRedis() {
	loginPool = createRedisAccess(RedisNameLogin)
	lgplayerpool = createRedisAccess(RedisNameDBPlayer)
	sessionPool = createRedisAccess(RedisNameSession)
	entityPool = createRedisAccess(RedisNameEntity)
	singletionPool = createRedisAccess(RedisNameSingleton)
	orderPool = createRedisAccess(RedisNameOrder)
	rankPool = createRedisAccess(RedisNameRank)
	// matchPool = createRedisAccess("MatchRedis")
	// pvpResultPool = createRedisAccess("PVPResultRedis")
}

// initConnectPool 初始化单个Redis
func initConnectPool(name string) {
	switch name {
	case RedisNameLogin:
		loginPool = createRedisAccess(RedisNameLogin)
	case RedisNameDBPlayer:
		lgplayerpool = createRedisAccess(RedisNameDBPlayer)
	case RedisNameSession:
		sessionPool = createRedisAccess(RedisNameSession)
	case RedisNameEntity:
		entityPool = createRedisAccess(RedisNameEntity)
	case RedisNameSingleton:
		singletionPool = createRedisAccess(RedisNameSingleton)
	case RedisNameOrder:
		orderPool = createRedisAccess(RedisNameOrder)
	case RedisNameRank:
		rankPool = createRedisAccess(RedisNameRank)
	// case "MatchRedis":
	// 	matchPool = createRedisAccess("MatchRedis")
	// case "PVPResultRedis":
	// 	pvpResultPool = createRedisAccess("PVPResultRedis")
	default:
		logger.Fatal("[initConnectPool] 不能支持 name ", name)
	}
}

// InitRedises 初始化一批pool
func InitRedises(names []string) {
	for _, name := range names {
		initConnectPool(name)
	}
}

// GetLoginRedis 获取一个redis连接
func GetLoginRedis() *redislib.RedisHandleModel {
	return loginPool.GetConn()
}

// Login服上的角色数据的保存
func GetDBPlayerRedis() *redislib.RedisHandleModel {
	return lgplayerpool.GetConn()
}

// GetSessionRedis 获取一个给服务器同步信息用的redis连接，用来同步DB数据的，还有session信息
func GetSessionRedis() *redislib.RedisHandleModel {
	return sessionPool.GetConn()
}

// GetEntityRedis 获取一个给服务器同步信息用的redis连接，Entity数据
func GetEntityRedis() *redislib.RedisHandleModel {
	return entityPool.GetConn()
}

// GetSingletonRedis 获取单实例redis连接，服务器注册
// 发现这个连接还被拿来使用写level等服务器的session这里可能会分出来
func GetSingletonRedis() *redislib.RedisHandleModel {
	return singletionPool.GetConn()
}

// 用于处理第三方发来的订单信息
func GetOrderRedis() *redislib.RedisHandleModel {
	return orderPool.GetConn()
}

// GetRankRedis 获取排名用的redis连接
func GetRankRedis() *redislib.RedisHandleModel {
	return rankPool.GetConn()
}

// GetMatchRedis 获取单实例redis连接
func GetMatchRedis() *redislib.RedisHandleModel {
	return matchPool.GetConn()
}

func GetPVPResultRedis() *redislib.RedisHandleModel {
	return pvpResultPool.GetConn()
}

// IsDBRedisValid DB redis是否可用
func IsDBRedisValid() bool {
	c := GetLoginRedis()
	defer c.Dispose()

	if _, err := c.Do(c.Ctx, "PING").Result(); err != nil {
		return false
	}

	return true
}

// IsServerRedisValid ForServer的redis是否可用
func IsServerRedisValid() bool {
	c := GetSessionRedis()
	defer c.Dispose()

	if _, err := c.Do(c.Ctx, "PING").Result(); err != nil {
		return false
	}

	return true
}

// IsSingletonRedisValid 单实例redis是否可用
func IsSingletonRedisValid() bool {
	c := GetSingletonRedis()
	defer c.Dispose()

	if _, err := c.Do(c.Ctx, "PING").Result(); err != nil {
		return false
	}

	return true
}

// IsRankRedisValid 排序redis是否可用
func IsRankRedisValid() bool {
	c := GetRankRedis()
	defer c.Dispose()

	if _, err := c.Do(c.Ctx, "PING").Result(); err != nil {
		return false
	}

	return true
}

func createRedisAccess(configDomain string) *redislib.RedisAccess {
	addr := viper.GetString(configDomain + ".Addr")
	index := viper.GetInt(configDomain + ".Index")
	// rawURL := fmt.Sprintf("redis://%s/%s", addr, index)
	pwd := viper.GetString(configDomain + ".Password")

	maxIdle := viper.GetInt(configDomain + ".MaxIdle")
	idleTimeout := time.Duration(viper.GetInt(configDomain + ".IdleTimeout"))
	maxActive := viper.GetInt(configDomain + ".MaxActive")
	result := redislib.NewRedisAccess(
		redislib.RedisSetAddr(addr),
		redislib.RedisSetAuth(pwd),
		redislib.RedisSetIdleTimeout(idleTimeout),
		redislib.RedisSetIndexDB(index),
		redislib.RedisSetMaxActive(maxActive),
		redislib.RedisSetMaxIdle(maxIdle),
	)
	return result
}

func checkHealth() {
	t := viper.GetInt("Config.RedisHealthCheckTimer")
	if t == 0 {
		t = 1
	}

	ticker := time.NewTicker(time.Duration(t) * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			redisRWMu.Lock()
			DBValid = IsDBRedisValid()
			SrvRedisValid = IsServerRedisValid()
			SingletonRedisValid = IsSingletonRedisValid()
			// RankRedisValid = IsRankRedisValid()
			redisRWMu.Unlock()
		}
	}
}

func CheckRedisStateForServer() bool {
	redisRWMu.RLock()
	defer redisRWMu.RUnlock()
	return DBValid && SrvRedisValid && SingletonRedisValid

}
